#include <fhe/core/Util.h>
#include <boost/algorithm/string.hpp>
#include <cstdio>
#include <cstdarg>
#include <stdexcept>

#ifdef BOOST_WINDOWS
#define snprintf _snprintf
#endif

namespace fhe
{
  namespace core
  {
    void Assert::assertNoMsg( bool cond, const char* scond, const char* file, int line )
    {
      if ( !cond )
      {
        char err[4098];
        snprintf( err, 4098, "FHE_ASSERT FAILED\ncond: %s\nfile: %s\nline: %d\n", scond, file, line );
        throw std::runtime_error( err );
      }
    }
    
    void Assert::assertMsg( bool cond, const char* scond, const char* file, int line, const char* fmt, ... )
    {
      if ( !cond )
      {
        va_list args;
        va_start( args, fmt );
        char buf[4098];
        vsnprintf( buf, 4098, fmt, args );
        va_end( args );
        char err[4098];
        snprintf( err, 4098, "FHE_ASSERT FAILED\ncond: %s\nfile: %s\nline: %d\nmsg: %s\n", scond, file, line, buf );
        throw std::runtime_error( err );
      }
    }
    
    void Assert::errorMsg( const char* file, int line, const char* fmt, ... )
    {
      va_list args;
      va_start( args, fmt );
      char buf[4098];
      vsnprintf( buf, 4098, fmt, args );
      va_end( args );
      char err[4098];
      snprintf( err, 4098, "FHE_ERROR\nfile: %s\nline: %d\nmsg: %s\n", file, line, buf );
      throw std::runtime_error( err );
    }
    
    void Log::log( const char* fmt, ... )
    {
      static FILE* fp = 0;
      if ( !fp )
      {
        fp = fopen( "fhelog.txt", "w" );
      }
      va_list args;
      va_start( args, fmt );
      char buf[4098];
      vsnprintf( buf, 4098, fmt, args );
      va_end( args );
      fprintf( fp, "%s\n", buf );
    }
    
    std::string StringUtil::replace( const std::string& _s, const std::string& from, const std::string& to )
    {
      std::string s = _s;
      size_t pos = 0;
      while ( ( pos = s.find( from, pos ) ) != std::string::npos )
      {
        s.replace( pos, from.size(), to );
        pos += to.size();
      }
      return s;
    }
    
    std::vector< std::string > StringUtil::split( const std::string& s, const std::string& delims )
    {
      std::vector< std::string > toks;
      boost::split( toks, s, boost::is_any_of( delims ) );
      return toks;
    }
  }
}
